package turritopsis

import (
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "errors"
    "fmt"
    "math/big"
    "strings"
    "adkr/pkg/crypto"
)
// Minimal proof-chain interface placeholders to align with paper terminology.
// These are lightweight and optional; callers can inject real implementations later.

// Evidence represents a generic evidence blob (opaque to the framework).
type Evidence struct {
    Type string
    Data []byte
}

// ProofVerifier defines a pluggable verifier.
// Return nil error to accept, or a non-nil error to reject.
type ProofVerifier interface {
    Verify(e Evidence) error
}

// NoopVerifier is a default verifier that always accepts.
type NoopVerifier struct{}

func (NoopVerifier) Verify(e Evidence) error { return nil }

// ProofEntry is a lightweight per-epoch proof record (for audit/logging only).
// It does not affect protocol correctness; cryptographic guarantees remain with
// MVBA/ACSS/BLS mechanisms. This mirrors the intent of a "proof chain" summary.
type ProofEntry struct {
    Epoch   int      `json:"epoch"`
    N       int      `json:"n"`
    F       int      `json:"f"`
    L       int      `json:"l"`
    Members []int    `json:"members,omitempty"`
    MembersHash string `json:"members_hash,omitempty"`
    AggSigSummary string `json:"agg_sig_summary,omitempty"`
    Sig []byte `json:"sig,omitempty"`
}


// BuildEpochDigest hashes epoch metadata to a 32-byte digest for signing.
func BuildEpochDigest(epoch int, n int, f int, l int, members []int) [32]byte {
    h := sha256.New()
    fmt.Fprintf(h, "e=%d;n=%d;f=%d;l=%d;members=", epoch, n, f, l)
    for i, m := range members {
        if i > 0 { h.Write([]byte{','}) }
        fmt.Fprintf(h, "%d", m)
    }
    var out [32]byte
    copy(out[:], h.Sum(nil))
    return out
}

// SignEpochDigest signs the digest with current curve (secp256k1 by default).
// For demo we use a deterministic private key derived from members hash, to avoid
// external key distribution in this experimental code.
func SignEpochDigest(digest [32]byte, membersHash string) ([]byte, error) {
    // derive a pseudo key from membersHash
    b, err := hex.DecodeString(strings.TrimPrefix(membersHash, "0x"))
    if err != nil || len(b) == 0 {
        sum := sha256.Sum256([]byte(membersHash))
        b = sum[:]
    }
    sk := crypto.NewSecp256k1Scalar(new(big.Int).SetBytes(b))
    if sk == nil {
        return nil, errors.New("failed to derive sk")
    }
    sig := sk.Sign(digest[:])
    out, err := json.Marshal(sig)
    if err != nil { return nil, err }
    return out, nil
}

// VerifyEpochSignature verifies signature against derived public key
func VerifyEpochSignature(digest [32]byte, membersHash string, sig []byte) bool {
    b, err := hex.DecodeString(strings.TrimPrefix(membersHash, "0x"))
    if err != nil || len(b) == 0 {
        sum := sha256.Sum256([]byte(membersHash))
        b = sum[:]
    }
    sk := crypto.NewSecp256k1Scalar(new(big.Int).SetBytes(b))
    if sk == nil { return false }
    var s crypto.Secp256k1Signature
    if err := json.Unmarshal(sig, &s); err != nil { return false }
    pk := crypto.GetSecp256k1Generator().ScalarMult(sk)
    return pk.Verify(digest[:], &s)
}

// BuildAndSignProof fills MembersHash, AggSigSummary and Sig.
func BuildAndSignProof(pe *ProofEntry) error {
    digest := BuildEpochDigest(pe.Epoch, pe.N, pe.F, pe.L, pe.Members)
    // members hash = sha256(members list)
    mh := sha256.Sum256([]byte(fmt.Sprintf("%v", pe.Members)))
    pe.MembersHash = "0x" + hex.EncodeToString(mh[:])
    sig, err := SignEpochDigest(digest, pe.MembersHash)
    if err != nil { return err }
    pe.Sig = sig
    pe.AggSigSummary = fmt.Sprintf("secp256k1|len=%d", len(sig))
    return nil
}

// SigVerifier implements ProofVerifier on ProofEntry
type SigVerifier struct{}

func (SigVerifier) Verify(e Evidence) error {
    // expect Evidence.Data to be hex(digest)||hex(sig)||membersHash
    parts := strings.Split(string(e.Data), "|")
    if len(parts) != 3 { return errors.New("invalid evidence format") }
    digB, err := hex.DecodeString(parts[0])
    if err != nil || len(digB) != 32 { return errors.New("bad digest") }
    var dig [32]byte; copy(dig[:], digB)
    sigB, err := hex.DecodeString(parts[1])
    if err != nil { return errors.New("bad sig") }
    mh := parts[2]
    if !VerifyEpochSignature(dig, mh, sigB) { return errors.New("sig verify failed") }
    return nil
}

